﻿// ## 2023/05/20 # 铃 # 铃 # 完全汉化,重构新增部分逻辑 ##
// ## 2022/02/14 # 江东新风 # 部分常量中文化 ##
// ## 2020/10/29 # 江东新风 # 同步马术书大神的更新##
// ## 2020/07/26 ##

namespace 撤离据点
{

	//---------------------------------------------------------------------------------------
	// 用户设置

	const bool 是否增加一次部队移动 = true;		// 增加一次部队移动
	const bool 是否出击瞬间应用逃跑效果 = true; // 出击瞬间应用逃跑效果

	const float 撤离时黄金食物回收率 = 0.95f; // 撤离时黄金/食物回收率
	const float 撤离时武器回收率 = 0.95f;	  // 撤离时武器回收

	//---------------------------------------------------------------------------------------

	class Main
	{

		Main()
		{
			pk::bind(202, pk::trigger202_t(onAIRunningOrder));
		}

		int retreat_skill1 = -1;
		int retreat_skill2 = -1;

		void onAIRunningOrder(pk::ai_context @context, pk::building @base, int cmd)
		{
			if (cmd == 据点AI_据点撤退 and 撤离据点(base))
			{
				int count = pk::get_idle_person_list(base).count;
				for (int k = 0; k < count / 3 + 1; k++)
				{
					push_retreat(base);
					push_retreat(base);
					push_retreat(base);
					push_retreat(base);
					push_retreat(base);
				}
			}
		}



//----------------------------------------------------------------------------------
//           撤离据点
//----------------------------------------------------------------------------------

// 判断是否需要撤
		bool 撤离据点(pk::building @base)
		{
			int enemy_troops3 = 0;

			auto range = pk::range(base.get_pos(), 1, 3 + (base.facility == 设施_都市 ? 1 : 0));
			for (int i = 0; i < int(range.length); i++)
			{
				auto unit = pk::get_unit(range[i]);
				if (pk::is_alive(unit))
				{
					int distance = pk::get_distance(base.get_pos(), range[i]);
					if (pk::is_enemy(base, unit))
					{
						if (distance <= 3)
							enemy_troops3 += unit.troops;
					}
				}
			}

			int base_troops = pk::get_troops(base);
			int base_hp = base.hp;

			// 当剩余耐久度非常危险时
			if (enemy_troops3 > 0 and base_hp < 2000)
				return true;
			// 当剩余部队数量非常危险时
			if (enemy_troops3 > 0 and base_troops < 3000 and base_troops < int(enemy_troops3 * 0.1f))
				return true;

			// 已经没有士气的时候
			if (enemy_troops3 > 0 and base_hp < 5000 and base.energy < 10)
				return true;

			return false;
		}

		bool push_retreat(pk::building @base)
		{
			// 检查是否有可用的武将。
			auto person_list = pk::get_idle_person_list(base);
			if (person_list.count == 0)
				return false;

			// 检查是否有相邻的撤退目的地。
			int target = getNearestBase(base);
			if (target == -1)
				return false;

			// 根据政治值/武力值比例排序。
			person_list.sort(function(a, b) {
				return (a.stat[武将能力_政治] / a.stat[武将能力_武力]) > (b.stat[武将能力_政治] / b.stat[武将能力_武力]);
			});
			pk::person @leader = pk::get_person(person_list[0].get_id());

			// 暂时加上逃跑效果
			if (是否出击瞬间应用逃跑效果)
			{
				retreat_skill1 = leader.skill; // 备份技能
				retreat_skill2 = leader.skill2; // 备份技能
				leader.skill = 特技_遁走;	  // 加上逃跑技能
				leader.skill2 = 特技_运输;	  // 加上逃跑技能
			}

			float supply_rate = pk::min(1.0f, pk::max(0.0f, 撤离时黄金食物回收率));
			float weapon_rate = pk::min(1.0f, pk::max(0.0f, 撤离时武器回收率));

			if (!pk::is_valid_pos(get_empty_pos(base.pos, 1, 1)))
			{
				auto arr = pk::range(base.pos, 1, 1);
				bool move_done = false;
				for (int i = 0; i < int(arr.length); i++)
				{
					pk::hex @hex = pk::get_hex(arr[i]);
					if (hex.has_unit)
					{
						pk::unit @unit = pk::get_unit(arr[i]);
						if (unit.get_force_id() != base.get_force_id())
							continue;
						if (unit.action_done == true)
							continue;
						//pk::trace(pk::format("{}部队移动命令", pk::decode(pk::get_name(unit))));
						pk::array<pk::point> arr_range = pk::get_movable_pos(unit);
						for (int j = 0; j < int(arr_range.length); j++)

						{
							if (pk::is_neighbor_pos(arr_range[j], unit.pos))
							{
								// array<pk::point> unit_path = {unit.pos, arr_range[j]}; // 临时措施
								array<pk::point> unit_path = { unit.pos, base.pos }; // 临时措施
								pk::move(unit, unit_path);
								move_done = true;
								break;
							}
						}
						if (move_done)
							break;
					}
				}
			}

			float 单次比例 = pk::max(1.0 - person_list.count * 0.05, 0.5);

			// 创建出征指令信息。
			pk::com_deploy_cmd_info cmd;
			@cmd.base = @base;
			cmd.type = 部队类型_运输;
			cmd.member[0] = leader.get_id();
			if (person_list.count >= 2)
				cmd.member[1] = person_list[1].get_id();
			if (person_list.count >= 3)
				cmd.member[2] = person_list[2].get_id();
			cmd.gold = pk::min(int(pk::get_gold(base) * 单次比例), 20000);
			cmd.food = int(pk::max((pk::min(pk::get_food(base) - 2000.0, pk::get_food(base) * 单次比例)), 1000.0));
			cmd.troops = int(pk::max((pk::min(pk::get_troops(base) - 2000.0, pk::get_troops(base) * 单次比例)), 100.0));
			int i = 0;
			for (int weapon_id = 0; weapon_id < 兵器_末; weapon_id++)
			{
				int weapon_amount = 0;
				if (weapon_id < 兵器_冲车)
					weapon_amount = pk::min(int(pk::get_weapon_amount(base, weapon_id) * weapon_rate), 100000);
				else
					weapon_amount = pk::min(int(pk::get_weapon_amount(base, weapon_id)), 100);

				if (weapon_amount > 0)
				{
					cmd.weapon_id[i] = weapon_id;
					cmd.weapon_amount[i] = weapon_amount;
					i++;
				}
			}
			cmd.order = 部队任务_移动;
			cmd.target_pos = pk::get_building(target).get_pos();

			// 出征。
			int unit_id = pk::command(cmd);
			pk::unit @unit_cmd = pk::get_unit(unit_id);
			if (pk::is_alive(unit_cmd))
				unit_cmd.action_done = (!是否增加一次部队移动);
			pk::run_order(unit_cmd);

			if (pk::is_in_screen(leader.get_pos()))
			{
				pk::say(pk::encode("快突破敌阵，撤退"), leader);

				pk::say(pk::encode("快坚持不住了,将军要放弃我们了吗?"), pk::get_person(武将_士兵));

			}

			// 暂时加上逃跑效果
			if (是否出击瞬间应用逃跑效果)
			{
				leader.skill = retreat_skill1; // 恢复技能
				leader.skill2 = retreat_skill2; // 恢复技能
			}

			return true;
		}

		// 获取最近我方据点
		pk::building @src_t;
		int getNearestBase(pk::building @src)
		{
			int best_dst = -1;
			int best_distance = 0;
			int src_id = src.get_id();
			pk::list<pk::building @> dst_list;
			@src_t = @src;
			pk::force @force = pk::get_force(src.get_force_id());

			// 撤离目标据点搜索
			if (pk::get_city_list(force).count <= 1 and src_id < 城市_末)
				return -1; // 如果这是我方最后一个城市，则无法撤退
			else
			{
				for (int i = 0; i < 据点_末; i++)
				{
					pk::building @dst = pk::get_building(i);
					int dst_id = dst.get_id();

					if (src_id != dst_id and src.get_force_id() == dst.get_force_id())
					{
						best_dst = dst_id;
						dst_list.add(dst); // 添加可撤离的据点列表
					}
				}
			}

			// 列出可用据点，按坐标距离和据点距离排序
			// (据点距离按升序排列，坐标距离按升序排列)
			if (dst_list.count == 0)
				best_dst = -1;
			else
			{
				dst_list.sort(function(a, b) {
					int build_dist_a = pk::get_building_distance(a.get_id(), main.src_t.get_id(), a.get_force_id());
					int build_dist_b = pk::get_building_distance(b.get_id(), main.src_t.get_id(), b.get_force_id());

					int pos_dist_a = pk::get_distance(a.pos, main.src_t.pos);
					int pos_dist_b = pk::get_distance(b.pos, main.src_t.pos);

					if (build_dist_a != build_dist_b)
						return (build_dist_a < build_dist_b);

					return (pos_dist_a < pos_dist_b);
				});
				best_dst = dst_list[0].get_id();
			}

			return best_dst;
		}

		pk::point get_empty_pos(pk::point pos, int distance_min, int distance_max)
		{
			array<pk::point> range_pos_arr = pk::range(pos, distance_min, distance_max);
			for (int arr_index = 0; arr_index < int(range_pos_arr.length); arr_index++)
			{
				pk::point range_pos = range_pos_arr[arr_index];
				if (!pk::is_valid_pos(range_pos))
					continue;

				pk::hex @hex = pk::get_hex(range_pos);
				if (hex.has_building)
					continue;
				if (hex.has_unit)
					continue;

				int terrain_id = hex.terrain;
				if (!pk::is_valid_terrain_id(terrain_id))
					continue;
				if (!pk::is_enabled_terrain(terrain_id))
					continue;

				return range_pos;
			}

			return pk::point(-1, -1);
		}
	};

	Main main;
}